package com.walle.ak47.commons.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.BitSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileUtils
{
	private static Logger LOG = LoggerFactory.getLogger( FileUtils.class ) ;

	private static final char[] HEX_TABLE = "0123456789abcdef".toCharArray();
	private static final char ESCAPE_CHAR = '%';
	public static final BitSet SAFE_NAMECHARS;
	public static final BitSet SAFE_PATHCHARS;

	static
	{
		SAFE_NAMECHARS = new BitSet(256);
		int i;
		for (i = 'a'; i <= 'z'; i++)
			SAFE_NAMECHARS.set(i);
		for (i = 'A'; i <= 'Z'; i++)
			SAFE_NAMECHARS.set(i);
		for (i = '0'; i <= '9'; i++)
			SAFE_NAMECHARS.set(i);
		SAFE_NAMECHARS.set('-');
		SAFE_NAMECHARS.set('_');
		SAFE_NAMECHARS.set('.');

		SAFE_PATHCHARS = (BitSet) SAFE_NAMECHARS.clone();
		SAFE_PATHCHARS.set(File.separatorChar);
		SAFE_PATHCHARS.set('/');
	}

	private static String escape(String s, BitSet safeChars)
	{
		byte[] bytes = s.getBytes();
		StringBuffer out = new StringBuffer(bytes.length);
		for (int i = 0; i < bytes.length; i++)
		{
			int c = bytes[i] & 0xff;
			if (safeChars.get(c) && c != ESCAPE_CHAR)
			{
				out.append((char) c);
			}
			else
			{
				out.append(ESCAPE_CHAR);
				out.append(HEX_TABLE[(c >> 4) & 0x0f]);
				out.append(HEX_TABLE[(c) & 0x0f]);
			}
		}
		return out.toString();
	}

	public static String escapePath(String path)
	{
		return escape(path, SAFE_PATHCHARS);
	}

	public static String escapeName(String name)
	{
		return escape(name, SAFE_NAMECHARS);
	}

	public static String unescape(String pathOrName)
	{
		ByteArrayOutputStream out = new ByteArrayOutputStream(pathOrName
				.length());
		for (int i = 0; i < pathOrName.length(); i++)
		{
			char c = pathOrName.charAt(i);
			if (c == ESCAPE_CHAR)
			{
				try
				{
					out.write(Integer.parseInt(pathOrName.substring(i + 1,
							i + 3), 16));
				}
				catch (NumberFormatException e)
				{
					throw new IllegalArgumentException();
				}
				i += 2;
			}
			else
				out.write(c);
		}
		return new String(out.toByteArray());
	}
	
	public static String getFileText(String _fileName)
	{
		InputStream input = null ;
		try
		{
			input = getFileInputStream( _fileName ) ;
			String content = IOUtils.toString( input ) ;
			
			return content ;
		}
		catch( Throwable err )
		{
			LOG.error( _fileName , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}
	}
	
	public static String getFileText( URL _url )
	{
		InputStream input = null ;
		try
		{
			input = _url.openStream() ;
			String content = IOUtils.toString( input ) ;
			
			return content ;
		}
		catch( Exception err )
		{
			LOG.error( _url.toString() , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}
	}
	
	public static String getFileText(File _file)
	{
		InputStream input = null ;
		try
		{
			input = getFileInputStream( _file ) ;
			String content = IOUtils.toString( input ) ;
			
			return content ;
		}
		catch( Throwable err )
		{
			LOG.error( _file.getAbsolutePath() , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly(input) ;
		}
	}
	
	public static String getFileText( URL _url , String _encoding )
	{
		InputStream input = null ;
		try
		{
			input = _url.openStream() ;
			String content = IOUtils.toString( input , _encoding ) ;
			
			return content ;
		}
		catch( Throwable err )
		{
			LOG.error( _url.toString() , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly(input) ;
		}
	}
	
	public static String getFileText(String _fileName, String _encoding)
	{
		InputStream input = null ;
		try
		{
			input = getFileInputStream( _fileName ) ;
			String content = IOUtils.toString( input , _encoding ) ;
			
			return content ;
		}
		catch( Throwable err )
		{
			LOG.error( _fileName , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}
	}
	
	public static String getFileText(File _file, String _encoding)
	{
		InputStream input = null ;
		try
		{
			input = getFileInputStream( _file ) ;
			String content = IOUtils.toString( input , _encoding ) ;
			
			return content ;
		}
		catch( Throwable err )
		{
			LOG.error( _file.getAbsolutePath() , err ) ;
			return "" ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}
	}

	public static byte[] getFileBytes(String _fileName)
	{
		return getFileByteStream(_fileName).toByteArray();
	}

	public static byte[] getFileBytes(File _file)
	{
		return getFileByteStream(_file).toByteArray();
	}
	
	public static byte[] getFileBytes( URL _url )
	{
		InputStream input = null ;
		try
		{
			input = _url.openStream() ;
			byte[] content = IOUtils.toByteArray( input ) ;
			
			return content ;
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}
	}

	public static InputStream getFileInputStream(String _fileName)
	{
		try
		{
			return new FileInputStream(_fileName);
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
	}
	
	public static InputStream getFileInputStream( URL _url )
	{
		try
		{
			return _url.openStream() ;
		}
		catch( Exception err )
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static InputStream getFileInputStream(File _file)
	{
		try
		{
			return new FileInputStream(_file );
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static ByteArrayOutputStream getFileByteStream(
			File _file)
	{
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		FileInputStream file = null;

		try
		{
			file = new FileInputStream(_file);
			int iReadCount = 0;
			byte[] temp = new byte[1024];

			do
			{
				iReadCount = file.read(temp);
				if (iReadCount > 0)
					buffer.write(temp, 0, iReadCount);
			} while (iReadCount > 0);

		}
		catch (Exception err)
		{
			LOG.error( _file.getAbsolutePath() , err ) ;
		}
		finally
		{
			try
			{
				if (file != null)
					file.close();
			}
			catch (Exception err)
			{
			}
		}

		return buffer;
	}

	public static ByteArrayOutputStream getFileByteStream(
			URL _url)
	{
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		InputStream input = null ;
		
		try
		{
			input = _url.openStream() ;
			IOUtils.copy( input , buffer ) ;
		}
		catch (Exception err)
		{
			throw new RuntimeException( err ) ;
		}
		finally
		{
			IOUtils.closeQuietly( input ) ;
		}

		return buffer ;
	}

	public static ByteArrayOutputStream getFileByteStream(
			String _fileName)
	{
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		FileInputStream file = null;

		try
		{
			file = new FileInputStream(_fileName);
			int iReadCount = 0;
			byte[] temp = new byte[1024];

			do
			{
				iReadCount = file.read(temp);
				if (iReadCount > 0)
					buffer.write(temp, 0, iReadCount);
			} while (iReadCount > 0);

		}
		catch (Exception err)
		{
			LOG.error( _fileName , err ) ;
		}
		finally
		{
			try
			{
				if (file != null)
					file.close();
			}
			catch (Exception err)
			{
			}
		}

		return buffer;
	}

	public static boolean writeFileText(String _fileName,
			String _strContent, boolean _isAppend)
	{
		FileWriter writer = null;

		try
		{
			writer = new FileWriter(_fileName, _isAppend);
			writer.write(_strContent);
			writer.flush();

			return true;
		}
		catch (Exception err)
		{
			LOG.error( _fileName , err ) ;
			return false;
		}
		finally
		{
			try
			{
				if (writer != null)
					writer.close();
			}
			catch (Exception err)
			{
			}
		}
	}

	public static boolean writeFileText(String _fileName, String _content)
	{
		return writeFileText(_fileName, _content, false);
	}

	public static boolean appendFileText(String _fileName, String _content)
	{
		return writeFileText(_fileName, _content, true);
	}

	public static boolean writeFileText(String _fileName,
			String _content, String _encoding, boolean _isAppend)
	{
		OutputStreamWriter writer = null;
		FileOutputStream stream = null ;

		try
		{
			stream = new FileOutputStream(	_fileName, _isAppend);

			writer = new OutputStreamWriter(stream, _encoding);
			writer.write(_content);
			writer.flush();

			return true;
		}
		catch (Exception err)
		{
			LOG.error( _fileName , err ) ;
			return false;
		}
		finally
		{
			IOUtils.closeQuietly(stream) ;
			try
			{
				if (writer != null)
					writer.close();
			}
			catch (Exception err)
			{
			}
		}
	}

	public static boolean writeFileText(String _fileName,
			String _strContent, String _strEncoding)
	{
		return writeFileText(_fileName, _strContent, _strEncoding, false);
	}

	public static boolean appendFileText(String _fileName,
			String _strContent, String _strEncoding)
	{
		return writeFileText(_fileName, _strContent, _strEncoding, true);
	}

	public static boolean writeFileBytes(String _fileName, byte[] _content,
			boolean _isAppend)
	{
		FileOutputStream writer = null;

		try
		{
			writer = new FileOutputStream(_fileName, _isAppend);
			writer.write(_content);
			writer.flush();

			return true;
		}
		catch (Exception err)
		{
			LOG.error( _fileName , err ) ;
			return false;
		}
		finally
		{
			try
			{
				if (writer != null)
					writer.close();
			}
			catch (Exception err)
			{
			}
		}
	}

	public static boolean writeFileBytes(String _fileName, byte[] _content)
	{
		return writeFileBytes(_fileName, _content, false);
	}

	public static boolean appendFileBytes(String _fileName, byte[] _content)
	{
		return writeFileBytes(_fileName, _content, true);
	}

	public static void mkdirs(String pathName)
	{
		File file = new File(pathName);
		if (file.exists())
			return;
		file.mkdirs();
	}

	public static boolean deleteFile(String _fileName)
	{
		try
		{
			File file = new File(_fileName);
			return file.delete();
		}
		catch (Exception err)
		{
			LOG.error( _fileName , err ) ;
			return false;
		}
	}
	
	public static boolean exists(String fileName)
	{
		File file = new File(fileName);

		return file.exists();
	}

	public static void deltree(String directory)
	{
		deltree(new File(directory));
	}

	public static void deltree(File directory)
	{
		if (directory.exists() && directory.isDirectory())
		{
			File[] fileArray = directory.listFiles();

			for (int i = 0; i < fileArray.length; i++)
			{
				if (fileArray[i].isDirectory())
				{
					deltree(fileArray[i]);
				}
				else
				{
					fileArray[i].delete();
				}
			}

			directory.delete();
		}
	}
}
